Português

Desbloqueie o poder da Federação GraphQL com Schema Stitching. Aprenda a construir uma API GraphQL unificada a partir de múltiplos serviços, melhorando a escalabilidade e a manutenibilidade.

Federação GraphQL: Schema Stitching - Um Guia Completo

No cenário em constante evolução do desenvolvimento de aplicações modernas, a necessidade de arquiteturas escaláveis e de fácil manutenção tornou-se primordial. Os microsserviços, com a sua modularidade inerente e capacidade de implementação independente, surgiram como uma solução popular. No entanto, gerir inúmeros microsserviços pode introduzir complexidades, especialmente quando se trata de expor uma API unificada para aplicações cliente. É aqui que a Federação GraphQL, e especificamente o Schema Stitching, entra em jogo.

O que é a Federação GraphQL?

A Federação GraphQL é uma arquitetura poderosa que lhe permite construir uma única API GraphQL unificada a partir de múltiplos serviços GraphQL subjacentes (frequentemente representando microsserviços). Permite que os desenvolvedores consultem dados em diferentes serviços como se fossem um único grafo, simplificando a experiência do cliente e reduzindo a necessidade de lógicas de orquestração complexas do lado do cliente.

Existem duas abordagens principais para a Federação GraphQL:

Este artigo foca-se no Schema Stitching, explorando os seus conceitos, benefícios, limitações e implementação prática.

Compreendendo o Schema Stitching

Schema Stitching é o processo de fundir múltiplos esquemas GraphQL num único esquema coeso. Este esquema unificado atua como uma fachada, escondendo a complexidade dos serviços subjacentes do cliente. Quando um cliente faz um pedido ao esquema unificado, o gateway encaminha inteligentemente o pedido para o(s) serviço(s) subjacente(s) apropriado(s), recupera os dados e combina os resultados antes de os devolver ao cliente.

Pense nisto da seguinte forma: Você tem vários restaurantes (serviços), cada um especializado em diferentes cozinhas. O Schema Stitching é como um menu universal que combina todos os pratos de cada restaurante. Quando um cliente faz um pedido a partir do menu universal, o pedido é encaminhado de forma inteligente para as cozinhas dos restaurantes apropriados, a comida é preparada e, em seguida, combinada numa única entrega para o cliente.

Conceitos Chave no Schema Stitching

Benefícios do Schema Stitching

O Schema Stitching oferece vários benefícios convincentes para organizações que adotam uma arquitetura de microsserviços:

Limitações do Schema Stitching

Embora o Schema Stitching ofereça inúmeras vantagens, é importante estar ciente das suas limitações:

Implementação Prática do Schema Stitching

Vamos percorrer um exemplo simplificado de como implementar o Schema Stitching usando Node.js e a biblioteca graphql-tools (uma escolha popular para a unificação de esquemas). Este exemplo envolve dois microsserviços: um Serviço de Utilizador e um Serviço de Produto.

1. Definir os Esquemas Remotos

Primeiro, defina os esquemas GraphQL para cada um dos serviços remotos.

Serviço de Utilizador (user-service.js):


const { buildSchema } = require('graphql');

const userSchema = buildSchema(`
  type User {
    id: ID!
    name: String
    email: String
  }

  type Query {
    user(id: ID!): User
  }
`);

const users = [
  { id: '1', name: 'Alice Smith', email: 'alice@example.com' },
  { id: '2', name: 'Bob Johnson', email: 'bob@example.com' },
];

const userRoot = {
  user: (args) => users.find(user => user.id === args.id),
};

module.exports = {
  schema: userSchema,
  rootValue: userRoot,
};

Serviço de Produto (product-service.js):


const { buildSchema } = require('graphql');

const productSchema = buildSchema(`
  type Product {
    id: ID!
    name: String
    price: Float
    userId: ID!  # Foreign key to User Service
  }

  type Query {
    product(id: ID!): Product
  }
`);

const products = [
  { id: '101', name: 'Laptop', price: 1200, userId: '1' },
  { id: '102', name: 'Smartphone', price: 800, userId: '2' },
];

const productRoot = {
  product: (args) => products.find(product => product.id === args.id),
};

module.exports = {
  schema: productSchema,
  rootValue: productRoot,
};

2. Criar o Serviço de Gateway

Agora, crie o serviço de gateway que irá unificar os dois esquemas.

Serviço de Gateway (gateway.js):


const { stitchSchemas } = require('@graphql-tools/stitch');
const { makeRemoteExecutableSchema } = require('@graphql-tools/wrap');
const { graphqlHTTP } = require('express-graphql');
const express = require('express');
const { introspectSchema } = require('@graphql-tools/wrap');
const { printSchema } = require('graphql');
const fetch = require('node-fetch');

async function createRemoteSchema(uri) {
  const fetcher = async (params) => {
    const response = await fetch(uri, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(params),
    });
    return response.json();
  };

  const schema = await introspectSchema(fetcher);
  return makeRemoteExecutableSchema({
    schema,
    fetcher,
  });
}

async function main() {
  const userSchema = await createRemoteSchema('http://localhost:4001/graphql');
  const productSchema = await createRemoteSchema('http://localhost:4002/graphql');

  const stitchedSchema = stitchSchemas({
    subschemas: [
      { schema: userSchema },
      { schema: productSchema },
    ],
    typeDefs: `
      extend type Product {
        user: User
      }
    `,
    resolvers: {
      Product: {
        user: {
          selectionSet: `{ userId }`,
          resolve(product, args, context, info) {
            return info.mergeInfo.delegateToSchema({
              schema: userSchema,
              operation: 'query',
              fieldName: 'user',
              args: {
                id: product.userId,
              },
              context,
              info,
            });
          },
        },
      },
    },
  });

  const app = express();
  app.use('/graphql', graphqlHTTP({
    schema: stitchedSchema,
    graphiql: true,
  }));

  app.listen(4000, () => console.log('Gateway server running on http://localhost:4000/graphql'));
}

main().catch(console.error);

3. Executar os Serviços

Terá de executar o Serviço de Utilizador e o Serviço de Produto em portas diferentes. Por exemplo:

Serviço de Utilizador (porta 4001):


const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./user-service');

const app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: rootValue,
  graphiql: true,
}));

app.listen(4001, () => console.log('User service running on http://localhost:4001/graphql'));

Serviço de Produto (porta 4002):


const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./product-service');

const app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: rootValue,
  graphiql: true,
}));

app.listen(4002, () => console.log('Product service running on http://localhost:4002/graphql'));

4. Consultar o Esquema Unificado

Agora pode consultar o esquema unificado através do gateway (a executar na porta 4000). Pode executar uma consulta como esta:


query {
  product(id: "101") {
    id
    name
    price
    user {
      id
      name
      email
    }
  }
}

Esta consulta recupera o produto com o ID "101" e também busca o utilizador associado do Serviço de Utilizador, demonstrando como o Schema Stitching lhe permite consultar dados de múltiplos serviços num único pedido.

Técnicas Avançadas de Schema Stitching

Além do exemplo básico, aqui estão algumas técnicas avançadas que podem ser usadas para melhorar a sua implementação de Schema Stitching:

Escolher entre Schema Stitching e Apollo Federation

Embora o Schema Stitching seja uma opção viável para a Federação GraphQL, a Apollo Federation tornou-se a escolha mais popular devido às suas funcionalidades avançadas e melhor experiência de desenvolvedor. Aqui está uma comparação das duas abordagens:

Funcionalidade Schema Stitching Apollo Federation
Definição do Esquema Usa a linguagem de esquema GraphQL existente Usa uma linguagem de esquema declarativa com diretivas
Planeamento de Consultas Requer delegação manual de consultas Planeamento automático de consultas pelo Apollo Gateway
Extensões de Tipo Suporte limitado Suporte nativo para extensões de tipo
Diretivas de Chave Não suportado Usa a diretiva @key para identificar entidades
Rastreamento Distribuído Requer implementação manual Suporte nativo para rastreamento distribuído
Ferramentas e Ecossistema Ferramentas menos maduras Ferramentas mais maduras e uma grande comunidade
Complexidade Pode ser complexo de gerir em sistemas grandes Projetado para sistemas grandes e complexos

Quando escolher o Schema Stitching:

Quando escolher a Apollo Federation:

Exemplos do Mundo Real e Casos de Uso

Aqui estão alguns exemplos do mundo real de como a Federação GraphQL, incluindo o Schema Stitching, pode ser usada:

Melhores Práticas para o Schema Stitching

Para garantir uma implementação bem-sucedida do Schema Stitching, siga estas melhores práticas:

Conclusão

A Federação GraphQL com Schema Stitching oferece uma abordagem poderosa para construir APIs unificadas a partir de múltiplos serviços numa arquitetura de microsserviços. Ao compreender os seus conceitos centrais, benefícios, limitações e técnicas de implementação, pode aproveitar o Schema Stitching para simplificar o acesso a dados, melhorar a escalabilidade e aumentar a manutenibilidade. Embora a Apollo Federation tenha surgido como uma solução mais avançada, o Schema Stitching permanece uma opção viável para cenários mais simples ou ao integrar serviços GraphQL existentes. Considere cuidadosamente as suas necessidades e requisitos específicos para escolher a melhor abordagem para a sua organização.